<template>
  <div class="appTemplate">
    <Header :title="'进阶案例-更新场景'" :back="true"/>
    <main ref="threeView" class="main"></main>
    <div class="buttonGroup">
      <button @click="animateClick">{{ animateActive?'停止动画':'启动动画' }}</button>
      <button @click="pointerClick">{{ pointerActive?'停止触控':'启动触控' }}</button>
    </div>
    <Footer />
  </div>
</template>

<script setup lang="ts">
import Header from '@/components/Header.vue';
import Footer from '@/components/Footer.vue';
import {onMounted, ref} from "vue";
// 导入整个 three.js核心库
import * as THREE from 'three';
import Stats from '&t/examples/jsm/libs/stats.module';
// 导入判断WebGL工具
import WebGL from "@/utils/WebGL";
import { ThreeUtil } from "@/utils/ThreeUtil";
import {GLSLFragDemo05} from "@/assets/glsl/fragment";
import {GLSLVertDemo05} from "@/assets/glsl/vertex";

THREE.Cache.enabled = true;
// 定义three场景显示区域
const threeView = ref();
const animateActive = ref(true);
const pointerActive = ref(true);
let threeUtil: ThreeUtil;

const animateClick = () => {
    if (animateActive.value) {
      cancelAnimationFrame(threeUtil.animateHandle);
    } else {
      animate();
    }
    animateActive.value = !animateActive.value;
}

const pointerClick = () => {
  // 似乎没有起到作用
  if (pointerActive.value) {
    pointerActive.value = !pointerActive.value;
    threeView.value.removeEventListener( 'pointerdown', onPointerDown );
  } else {
    pointerActive.value = !pointerActive.value;
    threeView.value.addEventListener( 'pointerdown', onPointerDown );
  }
}

onMounted(() => {
  if (WebGL.isWebGLAvailable()) {
    initThree();
    animate();
  } else {
    const warning = WebGL.getWebGLErrorMessage();
    threeView.value.appendChild(warning);
  }
})

const initThree = () => {
  threeUtil = new ThreeUtil();
  // 配置相关
  threeUtil.scene.background = new THREE.Color( 0x5a1216 );
  threeUtil.scene.fog = new THREE.Fog( 0xbe1480, 250, 1400 );
  threeUtil.camera.position.z = 200;
  threeUtil.renderer.setPixelRatio( window.devicePixelRatio );
  threeUtil.renderer.setSize( threeView.value.offsetWidth, threeView.value.offsetHeight, true );
  drawPoints();
  randerer();
  threeView.value.appendChild(threeUtil.renderer.domElement);
  threeView.value.style.touchAction = "none";
  threeView.value.addEventListener( 'pointerdown', onPointerDown );
  const stats = new Stats();
  stats.dom.style.position = "absolute";
  threeUtil.items['stats'] = stats;
  threeView.value.appendChild( stats.dom );
}

// 画点线
const drawPoints = () => {
  const amount = 100000;
  const radius = 200;

  const positions = new Float32Array( amount * 3 );
  const colors = new Float32Array( amount * 3 );
  const sizes = new Float32Array( amount );

  const vertex = new THREE.Vector3();
  const color = new THREE.Color( 0xffffff );
  for ( let i = 0; i < amount; i ++ ) {
    vertex.x = ( Math.random() * 2 - 1 ) * radius;
    vertex.y = ( Math.random() * 2 - 1 ) * radius;
    vertex.z = ( Math.random() * 2 - 1 ) * radius;
    vertex.toArray( positions, i * 3 );
    if ( vertex.x < 0 ) {
      color.setHSL( 0.5 + 0.1 * ( i / amount ), 0.7, 0.5 );
    } else {
      color.setHSL( 0.0 + 0.1 * ( i / amount ), 0.9, 0.5 );
    }
    color.toArray( colors, i * 3 );
    sizes[ i ] = 10;
  }
  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
  geometry.setAttribute( 'customColor', new THREE.BufferAttribute( colors, 3 ) );
  geometry.setAttribute( 'size', new THREE.BufferAttribute( sizes, 1 ) );
  const material = new THREE.ShaderMaterial( {
    uniforms: {
      color: { value: new THREE.Color( 0xffffff ) },
      pointTexture: { value: new THREE.TextureLoader().load( '/src/assets/textures/sprites/snowflake2.png' ) }
    },
    vertexShader: GLSLVertDemo05.drawPointsVertex,
    fragmentShader: GLSLFragDemo05.drawPointsFragment,
    blending: THREE.AdditiveBlending,
    depthTest: false,
    transparent: true

  } );
  const sphere = new THREE.Points( geometry, material );
  threeUtil.items['sphere'] = sphere;
  threeUtil.scene.add( sphere );
}

// 渲染
const randerer = () => {
  const time = Date.now() * 0.005;
  const sphere = threeUtil.items['sphere'];
  sphere.rotation.z = 0.01 * time;
  const geometry = sphere.geometry;
  const attributes = geometry.attributes;
  for ( let i = 0; i < attributes.size.array.length; i ++ ) {
    attributes.size.array[ i ] = 14 + 13 * Math.sin( 0.1 * i + time );
  }
  attributes.size.needsUpdate = true;
  threeUtil.renderer.render( threeUtil.scene, threeUtil.camera );
}

const animate = () => {
  threeUtil.animateHandle = requestAnimationFrame( animate );
  randerer();
  threeUtil.items['stats'].update();
}

const onPointerDown = (event: any) => {
  if ( event.isPrimary === false ) return;
  if ( pointerActive.value === false ) return;
  document.addEventListener( 'pointermove', onPointerMove );
  document.addEventListener( 'pointerup', onPointerUp );
}

const onPointerMove = ( event: any ) => {
  if ( event.isPrimary === false ) return;
  const pointerX = event.clientX - (window.innerWidth / 2);
  const pointerY = event.clientY - (window.innerHeight / 2);
  const targetRotationX = pointerX   * 0.02;
  const targetRotationY = pointerY   * 0.02;
  threeUtil.scene.rotation.y += (targetRotationX - threeUtil.scene.rotation.y) * 0.05;
  threeUtil.scene.rotation.x += (targetRotationY - threeUtil.scene.rotation.x) * 0.05;
  threeUtil.renderer.clear();
  threeUtil.renderer.render( threeUtil.scene, threeUtil.camera );
}

const onPointerUp = (event: any) => {
  if ( event.isPrimary === false ) return;
  document.removeEventListener( 'pointermove', onPointerMove );
  document.removeEventListener( 'pointerup', onPointerUp );
}
</script>

<style scoped>

</style>